package de.gis;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.SharedPreferences;
import android.util.Base64;
import android.util.Log;

public abstract class CouchCommunicator {
	protected String credentials;
	protected String dbUrl;

	public CouchCommunicator(String dbUrl, SharedPreferences prefs) {
		super();
		this.dbUrl = dbUrl;
		// dangerous to call non final method from constructor
		this.initialize(prefs);
	}

	public void initialize(SharedPreferences prefs) {
		credentials = prefs.getString(dbUrl, null);
	}

	protected HttpPut createHttpPut(String url) {
		HttpPut httpPut = new HttpPut(url);
		addCredentials(httpPut);
		return httpPut;
	}

	protected HttpPost createHttpPost(String url) {
		HttpPost httpPut = new HttpPost(url);
		addCredentials(httpPut);
		return httpPut;
	}

	private void addCredentials(HttpRequestBase request) {
		if (credentials != null) {
			request.setHeader("Authorization", convertCredentialsToBasicAuth());
		}
	}

	private String convertCredentialsToBasicAuth() {
		return "Basic "
				+ Base64.encodeToString(credentials.getBytes(), Base64.DEFAULT)
						.trim();
	}

	
	protected String getStringResponse(HttpUriRequest request) throws Exception {
		HttpResponse response = new DefaultHttpClient().execute(request);
		if (response.getStatusLine().getStatusCode() == 403
				|| response.getStatusLine().getStatusCode() == 401) {
			throw new UnauthorizedException(true /* isLocal */);
		}
		HttpEntity entity = response.getEntity();
		if (entity == null) {
			throw new Exception("Got empty response from couch db.");
		}

		String result = EntityUtils.toString(entity);
		Log.d("CC", "Creating DB result: " + result);
		return result;
	}
	
	protected JSONObject getResponse(HttpUriRequest request) throws Exception {
		String stringResponse = getStringResponse(request);
		checkError(request.getURI().toString(), stringResponse);
		return new JSONObject(stringResponse);
	}
	
	protected void checkError(String dbUrl, String json) throws Exception {
		try {
		JSONObject result = new JSONObject(json);
		if (result.has("error")) {
			if (result.has("reason")) {
				throw new Exception("Error speaking to " + dbUrl + ": "
						+ result.getString("reason"));
			} else {
				throw new Exception("Error speaking to " + dbUrl
						+ ", reason unknown");
			}
		}
		} catch (JSONException ex) {
			// it is not json object, maybe an array or so, but no error
		}
		
	}
	
	protected JSONArray getJSonArrayResponse(HttpUriRequest request) throws Exception {
		String stringResponse = getStringResponse(request);
		checkError(request.getURI().toString(), stringResponse);
		return new JSONArray(stringResponse);
	}

	protected void addJson(HttpEntityEnclosingRequest request, String requestData) {
		ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData
				.getBytes());
		byteArrayEntity.setContentType("application/json");
		request.setEntity(byteArrayEntity);
		Log.d("CC", "Set request data: " + requestData);
	}

	public abstract void doit() throws Exception;
}
